package service

import (
	"errors"
	"fmt"
	"net/url"
	"ssdevice/common/constant"
	"strings"

	"gitee.com/sansaniot/ssiot-core/httpmvc/service"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"

	cDto "ssdevice/common/dto"
	"ssdevice/internal/device/models"
	"ssdevice/internal/device/models/command"
	"ssdevice/internal/device/models/query"
)

type Variable struct {
	sysDevModel    *models.SysDev
	devSchemaModel *models.SysDevSchema
	devConfigModel *models.SysDevConfig
	devSensorModel *models.SysDevSensor
	variableModel  *models.SysDevVariable
	service.Service
}

func (d *Variable) SetDevModel(m *models.SysDev) *Variable {
	d.sysDevModel = m
	return d
}

func (d *Variable) SetSchemaModel(m *models.SysDevSchema) *Variable {
	d.devSchemaModel = m
	return d
}

func (d *Variable) SetConfigModel(m *models.SysDevConfig) *Variable {
	d.devConfigModel = m
	return d
}

func (d *Variable) SetSensorModel(m *models.SysDevSensor) *Variable {
	d.devSensorModel = m
	return d
}

func (d *Variable) SetVariableModel(m *models.SysDevVariable) *Variable {
	d.variableModel = m
	return d
}

func (d *Variable) SetAllModel() {
	d.sysDevModel = &models.SysDev{}
	d.devSchemaModel = &models.SysDevSchema{}
	d.devConfigModel = &models.SysDevConfig{}
	d.devSensorModel = &models.SysDevSensor{}
	d.variableModel = &models.SysDevVariable{}
	d.sysDevModel.Orm = d.Orm
	d.devSchemaModel.Orm = d.Orm
	d.devConfigModel.Orm = d.Orm
	d.devSensorModel.Orm = d.Orm
	d.variableModel.Orm = d.Orm
}

// 添加设备
func (d *Variable) UpsertVariable(req *command.VariableInsertReq) (err error, devVariable models.SysDevVariable) {
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{Sn: req.Sn})); err != nil {
		return
	}
	if sysDev.DeptId == constant.PublicGroupId && req.UserId != "1" {
		err = errors.New("没权限操作公共分组资源")
		return
	}
	req.Generate(&devVariable)
	if err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.variableModel.Orm = tx
		// 添加变量
		if err = d.variableModel.Upsert(&devVariable, []string{"sn", "key"}...); err != nil {
			return err
		}
		// 更新设备schema
		if err = devVariableSchema(tx, devVariable); err != nil {
			return err
		}
		// 更新设备config
		if err = devVariableProfile(tx, devVariable); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return
	}
	return
}

// 删除变量
func (d *Variable) DeleteVariable(req *command.VariableDeleteReq) (err error) {
	if len(req.SnKey) == 0 {
		return
	}
	err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.variableModel.Orm = tx
		// 批量操作
		for sn, keys := range req.SnKey {
			sysDev := models.SysDev{}
			_ = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{Sn: sn}))
			if sysDev.DeptId == constant.PublicGroupId && req.UserId != "1" {
				return errors.New("没权限操作公共分组资源")
			}
			// 变量表
			if err = d.variableModel.Delete(d.variableModel, cDto.MakeCondition(query.SysDevVariableQuery{Sn: sn, KeyIn: keys})); err != nil {
				return err
			}
			for _, key := range keys {
				// profile
				jsonPath := fmt.Sprintf("{config,sensor,%s}", strings.ReplaceAll(key, ".", ","))
				sql := "update sys_dev_config set data = jsonb_delete_path(data::jsonb, '" + jsonPath + "') where dev_sn = '%s'"
				sql = fmt.Sprintf(sql, sn)
				if err = tx.Raw(sql).Scan(d.devConfigModel).Error; err != nil {
					return err
				}
				jsonPath = fmt.Sprintf("{sensor,%s}", strings.ReplaceAll(key, ".", ","))
				sql = "update sys_dev_sensor set data = jsonb_delete_path(data::jsonb, '" + jsonPath + "') where dev_sn = '%s'"
				sql = fmt.Sprintf(sql, sn)
				if err = tx.Raw(sql).Scan(d.devSensorModel).Error; err != nil {
					return err
				}
				// schema (.变成 .properties. )
				kk := strings.ReplaceAll(key, ".", ",properties,")
				jsonPath = fmt.Sprintf("{properties,sensor,properties,%s}", kk)
				sql = "update sys_dev_schema set schema = jsonb_delete_path(schema::jsonb, '" + jsonPath + "') where dev_sn = '%s'"
				sql = fmt.Sprintf(sql, sn)
				if err = tx.Raw(sql).Scan(d.devSchemaModel).Error; err != nil {
					return err
				}
				// schema config
				jsonPath = fmt.Sprintf("{properties,config,properties,sensor,properties,%s}", kk)
				sql = "update sys_dev_schema set schema = jsonb_delete_path(schema::jsonb, '" + jsonPath + "') where dev_sn = '%s'"
				sql = fmt.Sprintf(sql, sn)
				if err = tx.Raw(sql).Scan(d.devSchemaModel).Error; err != nil {
					return err
				}
			}
		}
		return nil
	})
	return
}

// 导出变量
func (d *Variable) ExportVariable(c *gin.Context, req *query.SysDevVariableQuery) error {
	req.PageIndex = 0
	vars := make([]models.SysDevVariable, 0)
	if err, result := d.variableModel.FindVariableList(req); err != nil {
		return err
	} else {
		vars = result.([]models.SysDevVariable)
	}
	if len(vars) == 0 {
		return errors.New("查无数据")
	}
	// 生成模板
	f := excelize.NewFile()
	defer f.Close()
	// 模板内容
	if err := FillExportVariable(f, vars); err != nil {
		return err
	}
	// 删除excelize的默认sheet
	f.DeleteSheet("Sheet1")
	// 响应文件流
	fileName := fmt.Sprintf("设备变量.xlsx")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename*=utf-8''%s", url.QueryEscape(fileName)))
	c.Header("File-Name", url.QueryEscape(fileName))
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8")
	if _, err := f.WriteTo(c.Writer); err != nil {
		_, _ = fmt.Fprintf(c.Writer, err.Error())
		return err
	}
	return nil
}

func (d *Variable) ImportVariable(c *gin.Context, req *query.SysDevVariableQuery) error {
	// 获取文件对象
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		return err
	}
	if file == nil || !strings.HasSuffix(header.Filename, ".xlsx") {
		return errors.New("非法文件，请使用正确的文件导入")
	}
	defer file.Close()
	f, err := excelize.OpenReader(file)
	if err != nil {
		return err
	}
	// 执行导入
	if err = ImportVariableData(d.variableModel, f, req.UserId); err != nil {
		return err
	}
	return nil
}
